/**
 * 检查一个值是否是一个对象
 * @param {*} value 
 * @returns 
 */
export const isObject = (value) => value !== null && typeof value === 'object' && !Array.isArray(value);

/**
 * 检查一个值是否是一个数组
 * @param {*} value
 */
export const isArray = Array.isArray;

/**
 * 检查一个值是否是一个字符串
 * @param {*} value 
 * @returns 
 */
export const isString = (value) => typeof value === 'string';

/**
 * 检查一个值是否是一个数字
 * @param {*} value 
 * @returns 
 */
export const isSet = (value) => value instanceof Set;

/**
 * 检查一个值是否是一个函数
 * @param {*} value 
 * @returns 
 */
export const isFunction = (value) => typeof value === 'function';

/**
 * 检查一个值是否是一个可调用的对象
 * @param {*} value 
 * @returns 
 */
export const isCallable = (value) => isObject(value) && isFunction(value);

/**
 * 检查一个值是否是一个JSON对象
 * @param {*} body 
 * @returns 
 */
export const isJson = function (body) {
    return !(
        !body ||
        typeof body === 'string' ||
        typeof body.pipe === 'function' ||
        Buffer.isBuffer(body)
    )
}

/**
 * 休眠时间
 * @param {*} time 
 * @param {*} isMs 
 * @returns 
 */
export const sleep = (time, isMs = false) => {
    return new Promise((resolve) => setTimeout(resolve, isMs ? time : time * 1000));
}

/**
 * 检查一个值是否为空
 * @param {any} data - 要检查的值
 * @returns {boolean} - 如果值为空则返回 true, 否则返回 false
 */
export const empty = function (data) {
    if (isObject(data) || isArray(data)) {
        return Object.keys(data).length === 0;
    }

    if (isSet(data)) {
        return data.size === 0;
    }
    return data == '' || data == null || data === void 0;
};

/**
 * 使用".符号从数组或对象中获取一个项目
 * @param {Object|Array} target - 目标对象或数组
 * @param {string|array} key - 要获取的键
 * @param {any} [defaultValue=null] - 如果键不存在的默认值
 * @returns {any} - 键的值或默认值
 */
export const dataGet = function (target, key, defaultValue = null) {
    if (key === null) {
        return target;
    }

    const keys = isArray(key) ? key : key.split('.');
    for (let segment of keys) {
        if (segment === '*') {
            if (!isArray(target) && !isObject(target)) {
                return defaultValue;
            }

            const result = [];
            for (let item of target) {
                result.push(dataGet(item, keys.slice(1)));
            }

            return result;
        }

        if (isObject(target) && target.hasOwnProperty(segment)) {
            target = target[segment];
        } else if (isArray(target) && segment < target.length) {
            target = target[segment];
        } else {
            return defaultValue;
        }
    }

    return target;
};

/**
 * 使用"."符号在数组或对象上设置一个项目
 * @param {Object|Array} target - 目标对象或数组
 * @param {string|array} key - 要设置的键
 * @param {any} value - 要设置的值
 * @param {boolean} [overwrite=true] - 是否覆盖现有值
 * @returns {Object|Array} - 修改后的目标
 */
export const dataSet = function (target, key, value, overwrite = true) {
    const keys = isArray(key) ? key : key.split('.');
    let segment;

    while ((segment = keys.shift()) !== void 0) {
        if (segment === '*') {
            if (!isArray(target)) {
                target = [];
            }

            if (keys.length) {
                for (let i = 0; i < target.length; i++) {
                    dataSet(target[i], keys, value, overwrite);
                }
            } else if (overwrite) {
                for (let i = 0; i < target.length; i++) {
                    target[i] = value;
                }
            }
        } else if (isObject(target)) {
            if (keys.length) {
                if (!target.hasOwnProperty(segment)) {
                    target[segment] = {};
                }

                dataSet(target[segment], keys, value, overwrite);
            } else if (overwrite || !target.hasOwnProperty(segment)) {
                target[segment] = value;
            }
        } else if (isArray(target)) {
            if (keys.length) {
                if (target[segment] === void 0) {
                    target[segment] = {};
                }

                dataSet(target[segment], keys, value, overwrite);
            } else if (overwrite || target[segment] === void 0) {
                target[segment] = value;
            }
        } else {
            target = {};
            if (keys.length) {
                dataSet(target[segment], keys, value, overwrite);
            } else if (overwrite) {
                target[segment] = value;
            }
        }
    }

    return target;
};

/**
 * 使用"."符号从数组或对象中移除一个项目
 * @param {Object|Array} target - 目标对象或数组
 * @param {string|array} key - 要移除的键
 * @returns {Object|Array} - 修改后的目标
 */
const dataForget = function (target, key) {
    const keys = isArray(key) ? key : key.split('.');
    let segment;

    while ((segment = keys.shift()) !== void 0) {
        if (segment === '*') {
            if (isArray(target)) {
                for (let i = 0; i < target.length; i++) {
                    dataForget(target[i], keys);
                }
            }
        } else if (isObject(target)) {
            if (keys.length) {
                if (target.hasOwnProperty(segment)) {
                    dataForget(target[segment], keys);
                }
            } else {
                delete target[segment];
            }
        } else if (isArray(target)) {
            if (keys.length) {
                if (target[segment] !== void 0) {
                    dataForget(target[segment], keys);
                }
            } else {
                target.splice(segment, 1);
            }
        }
    }

    return target;
};

/**
 * 获取数组的第一个元素
 * @param {Array} array - 要获取第一个元素的数组
 * @returns {any} - 数组的第一个元素
 */
export const dataHead = function (array) {
    return array[0];
};

/**
 * 获取数组的最后一个元素
 * @param {Array} array - 要获取最后一个元素的数组
 * @returns {any} - 数组的最后一个元素
 */
export const dataLast = function (array) {
    return array[array.length - 1];
};

/**
 * 返回给定值的默认值
 * @param {any} value - 要返回的值
 * @param {...any} args - 如果值是函数,则为附加参数
 * @returns {any} - 值或函数的结果
 */
export const dataValue = function (value, ...args) {
    return typeof value === 'function' ? value(...args) : value;
};

// 是否可以迭代
export const isIterable = (value) => {
    return value !== null && typeof value[Symbol.iterator] === 'function';
}